#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>      /* defines MAX_INPUT         */
#include <string.h>      /* prototype for strlen()    */
#include <termios.h>
#include <time.h>        /* prototype for nanosleep() */
#include <sys/time.h>    /* for select()              */
#include <sys/ioctl.h>   /* defines N_TTY             */
#include <sys/types.h>

int
serial_open(char *device)
{
  int fd, oldflags;

  /* O_NONBLOCK allows open even with no carrier detect */
  if (-1 != (fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK))) {
    /* clear O_NONBLOCK to allow read() and write() to block */
    if ((-1 != (oldflags = fcntl(fd, F_GETFL, 0))) &&
        (-1 != fcntl(fd, F_SETFL, oldflags & ~O_NONBLOCK))) {

      /* flush input and output */
      if (-1 == tcflush(fd, TCIOFLUSH)) {
        close(fd);
        return -1;
      }

    } else {
      close(fd);
      return -1;
    }
  }
	//printf("* device %s [%d]\n",device,fd);
  return fd;
}


/*
 * configure the serial port
 *
 *    hardware flow control, 8n1, full duplex, and
 *    non-canonical input.
 */

#define TERMSIZE (offsetof (struct termios, c_cc[NCCS]))

int
serial_cnfg(int fd,int aBAUD)
{
  struct termios tty, stty;

  tcgetattr(fd, &tty);  
#define BAUD B9600
#define CFLAGS  (CRTSCTS | CS8 | 0 | CREAD)
#define IFLAGS  (IGNBRK | IGNPAR)
  
  /* raw io, hardware flow control, 8n1 */
  tty.c_iflag     = IFLAGS;  /* input flags          */
  tty.c_cflag     = CFLAGS; /* control flags        */
  tty.c_lflag     = 0;      /* local flags          */
  tty.c_oflag     = 0;      /* output flags         */
  tty.c_cc[VMIN]  = 1;      /* wait for 1 character */
  tty.c_cc[VTIME] = 0;      /* turn off timer       */

#ifdef __linux__
  /* for linux only */
  tty.c_line      = N_TTY;  /* set line discipline  */
#endif

  cfsetospeed(&tty, BAUD);  /* set the bit rate     */
  cfsetispeed(&tty, BAUD);
    
  if (tcsetattr(fd, TCSADRAIN, &tty) || tcgetattr(fd, &stty)) {
    return -1;
  }

  /* verify the changes were actually made */
  return memcmp(&tty, &stty, TERMSIZE) ? -1 : 0;
}
